package com.me.study.jdk8.lambda;

import com.me.common.util.SleepUtil;
import org.junit.Test;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <pre>JDK1.8 新特性：Lambda 表达式</pre>
 *
 * 三种编写方式：<p>
 *     1，expression: 单条语句表达式    <p>
 *     2，statement: 代码块 <p>
 *     3，reference: 方法引用    <p>
 *
 * @author ME
 * @date   2019/4/25
 */
public class TestLambda {

    /**
     * 匿名内部类 --> lambda --> 方法引用        <p>
     * 一步步简化成反直观的语法，如：getConsumer3() 中的 doSomething() 明明没有返回值，却可以返回。why？    <p>
     * 因为返回的是方法本身呀。
     */
    @Test
    public void test1() {
        getConsumer3().accept("233333");
    }

    /** 匿名内部类 */
    public <T> Consumer<T> getConsumer1() {
        return new Consumer<T>() {
            @Override
            public void accept(T str) {
                doSomething(str);
            }
        };
    }

    /** lambda */
    public <T> Consumer<T> getConsumer2() {
        return str -> doSomething(str);
    }

    /** 方法引用 */
    public <T> Consumer<T> getConsumer3() {
        return this::doSomething;
    }

    public <T> void doSomething(T t) {
        // TODO do something
        System.out.println(t);
    }

    @Test
    public void test() {
        // 线程创建：jdk6 写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello, jdk6 ");
            }
        }).start();
        SleepUtil.ms(50);// 睡眠50ms，保证打印次序

        // Lambda1：线程创建
        System.out.println("\nLambda1：线程创建");
        new Thread(() -> System.out.println("hello, lambda")).start();
        SleepUtil.ms(50);// 睡眠50ms，保证打印次序

        // Lambda2：Lambda 传递函数
        System.out.println("\nLambda2：Lambda 传递函数");
        Integer integer = str2Int(str -> {
            // str 强转成 [0, 99]的 int型
            int i = Integer.parseInt(str);
            if (i < 0) {
                return 0;
            } else if (i > 99) {
                return 99;
            } else {
                return i;
            }
        }, "123");
        System.out.println(integer);

        // Lambda3：Lambda 传递条件
        System.out.println("\nLambda3：Lambda 传递条件");
        List<Apple> appleList = getAppleByPredicate(apple -> apple.getColor().equals("red"));
        StringBuffer sb = new StringBuffer("红色的苹果有: ");
        for (Apple apple : appleList) {
            sb.append(apple.getName()).append("、");
        }
        System.out.println(sb.toString());

        // 普通排序
        Collections.sort(appleStore, (Apple apple1, Apple apple2) -> apple1.getWeight() - apple2.getWeight());
        Collections.sort(appleStore, Comparator.comparingInt(Apple::getWeight));
        // 基于 stream并行流 的排序
        appleStore.stream().sorted((Apple apple1, Apple apple2) -> apple1.getWeight() - apple2.getWeight())
            .collect(Collectors.toList());
    }

    /**
     * Lambda2：Lambda 传递一段处理逻辑
     *
     * @param function Lambda表示的一段处理逻辑
     * @param str Lambda的入参
     * @return
     */
    public Integer str2Int(Function<String, Integer> function, String str) {
        return function.apply(str);
    }

    /** 苹果清单 */
    private final List<Apple> appleStore = new ArrayList<>();
    /** 初始化苹果清单 */
    {
        Apple a1 = new Apple("青苹果", "green", 150, "山东");
        Apple a2 = new Apple("红富士", "red", 300, "山东");
        Apple a3 = new Apple("金帅", "yellow", 180, "云南");
        Apple a4 = new Apple("蛇果", "red", 200, "美国");
        appleStore.add(a1);
        appleStore.add(a2);
        appleStore.add(a3);
        appleStore.add(a4);
    }

    /**
     * 筛选出符合条件的苹果   <p>
     * Lambda3：Lambda 传递一个条件
     *
     * @param predicate 判断条件
     */
    public List<Apple> getAppleByPredicate(Predicate<Apple> predicate) {
        List<Apple> result;
        // for (Apple apple : appleStore) {
        //     if (predicate.check(apple)) {
        //         result.add(apple);
        //     }
        // }

        // 基于 stream 进行过滤
        result = appleStore.stream().filter(predicate).collect(Collectors.toList());
        return result;
    }
}
